/**
* codesvr主控类
* @author rapier
*/

#ifndef __CODESRV_CTRL_H__
#define __CODESRV_CTRL_H__

#include "codedef.h"
#include "codeconfig.h"

#define CodeNetEpollObject CTEpollObject<CCodeSvrCtrl>
#define CodeNetShmQueue CTShmQueue<CCodeSvrCtrl>

class CCodeSvrCtrl
{
protected:
    CTEpoll             m_stEpoll;      ///< epoll对象
    CodeNetShmQueue     m_stEnpShm;     ///< 与enp程序通讯的接口
    CodeNetShmQueue     m_stMainShm;    ///< 与mp程序通讯的接口	

    CTCodeStream  m_stEnpIn;  ///< s表示其为一个通道，Enp为通道名称，In表示该通道用于输入
    CTCodeStream  m_stEnpOut; ///< 同上
    CTCodeStream  m_stMainIn;
    CTCodeStream  m_stMainOut;
    CTCodeStream  m_stDecrypt;

    CTCodeStream  m_stStrToHex;

    CTMsgHead m_stDataHead;
    CEnpNetHead m_stEnphead;

    SBUFF  m_stEnpBuffIn;
    SBUFF  m_stEnpBuffOut;
    SBUFF  m_stMainBuffIn;
    SBUFF  m_stMainBuffOut;
    SBUFF  m_stDecryptBuf;          //解密后的协议存放的buf

    SBUFF  m_stStrToHexBuf;         //用于从str解码到hex的buf

    enum
    {
        EPOLL_SIZE = 1024,
        EPOLL_WAIT_SIZE = 1024,
    };

public:
    static bool s_bReloadConfig;
	static bool s_bExit;

    CCodeSvrCtrl(void);
	~CCodeSvrCtrl(void);

    void Init(void);
	void Run(void);
	void Exit(void);

    static void sigusr1_handle(int iSigVal);
    static void sigusr2_handle(int iSigVal);

protected:
    void OnEnpQueueEvent(CodeNetEpollObject* pstObject, SOCKET iSocket, int iEvent);
    void OnMainQueueEvent(CodeNetEpollObject* pstObject, SOCKET iSocket, int iEvent);

    /**
    * 将管道缓冲区里的数据推入共享内存
    */
    void Push();

    /**
    * 将共享内存里的数据拉入管道缓冲区
    */
    int Pull();
 
    int Poll();

    /**
    * 转换数据codesvrctrl.cpp
    */
    int ConvertDataUp();
    int ConvertDataDown();

    /**
    * 实现对具体数据结构的解析
    */
    int FindTypeAndConvertUp();
    int FindTypeAndConvertDown();

    //用来辅助ConvertUp，在编码前对协议指进行修改
    template<typename ClassName>
    void AssistConverUp(ClassName& t)
    {
        ;               //缺省情况下不用做任何操作，需要做操作的协议需要特化该函数
    }

    template<typename ClassName>
    int ConvertUp(const char* pszClassName)
    {
        int iRet = 0;
        ClassName st;

        switch (m_stEnphead.ucDeodeMethod)
        {
        case CODE_STRING :
            {
                CodeConvert(m_stEnpIn, st, pszClassName, string_decode());
                iRet = m_stEnpIn.m_iRet;
            }
            break;
        case CODE_BIN :
            {
                CodeConvert(m_stEnpIn, st, pszClassName, bin_decode());
                iRet = m_stEnpIn.m_iRet;
            }
            break;
        default:
            CT_WARNING(("recv unknown pkg"));
            return -1;
        }

        if (iRet != 0)
        {
            CT_WARNING(("codesvr decode data body err iRet=%d", iRet));
            CT_TRACE(("buffdata :"));
            CT_TRACEBINARY((m_stEnpBuffIn.streamBuffs, m_stEnpBuffIn._offset));
            return -1;
        }

        AssistConverUp(st);

        m_stMainOut.m_ushPos += sizeof(CEnpNetHead);
        CodeConvert(m_stMainOut, m_stDataHead, "CTMsgHead", bin_encode());
        if (m_stMainOut.m_iRet != 0)
        {
            CT_WARNING(("codesvr bin encode data head err iRet=%d", m_stMainOut.m_iRet));
            CT_WARNING(("datahead Info MsgID = %d MsgType = %d more Info see Trace", m_stDataHead.shMsgID, m_stDataHead.shMsgType));
            CT_TRACEBINARY(((char *)&m_stDataHead, sizeof(CTMsgHead)));
            return -1;
        }

        CodeConvert(m_stMainOut, st, pszClassName, bin_encode());
        if (m_stMainOut.m_iRet != 0)
        {
            CT_WARNING(("codesvr bin decode data body err iRet=%d", m_stEnpIn.m_iRet));
            CT_WARNING(("datahead Info MsgID = %d MsgType = %d  boby name %s more Info see Trace",
                m_stDataHead.shMsgID, m_stDataHead.shMsgType));
            CT_TRACEBINARY(((char *)&st, sizeof(ClassName)));
            return -1;
        }

        m_stEnphead.unDataLength = m_stMainOut.m_ushPos - sizeof(CEnpNetHead);
        memcpy(m_stMainOut.m_pszBuf, &m_stEnphead, sizeof(CEnpNetHead));
        CT_TRACE(("msg len = %d, data len = %d", m_stEnphead.unDataLength, m_stMainOut.m_ushPos));
        m_stMainBuffOut._offset = m_stMainOut.m_ushPos;
        return 0;
    }

    template<typename ClassName>
    int ConvertDown(const char* pszClassName)
    {
        ClassName st;
        CodeConvert(m_stMainIn, st, pszClassName, bin_decode());
        if (m_stMainIn.m_iRet != 0)
        {
            CT_WARNING(("codesvr bin decode data boby err iRet=%d", m_stMainIn.m_iRet));
            CT_TRACE(("buffdata :"));
            CT_TRACEBINARY((m_stMainBuffIn.streamBuffs, m_stMainBuffIn._offset));
            return -1;
        }

        m_stEnpOut.m_ushPos = sizeof(CEnpNetHead);
        switch (m_stEnphead.ucEnodeMethod)
        {
        case CODE_STRING :
            {
                CodeConvert(m_stEnpOut, m_stDataHead, "CTMsgHead", string_encode());
                CodeConvert(m_stEnpOut, st, pszClassName, string_encode());
                if (m_stEnpOut.m_iRet)
                {
                    CT_WARNING(("codesvr string encode err iRet=%d", m_stEnpOut.m_iRet));
                    CT_TRACE(("datahead Info MsgID = %d MsgType = %d  boby name %s more Info see Trace",
                        m_stDataHead.shMsgID, m_stDataHead.shMsgType));
                    CT_TRACEBINARY(((char *)&m_stDataHead, sizeof(CTMsgHead)));
                    CT_TRACEBINARY(((char *)&st, sizeof(ClassName)));
                    return -1;
                }

                //结束符
                char chEndFlag = 0;
                CodeConvert(m_stEnpOut, chEndFlag, "char", bin_encode());
            }
            break;
        case CODE_BIN :
            {
                CodeConvert(m_stEnpOut, m_stDataHead, "CTMsgHead", bin_encode());
                CodeConvert(m_stEnpOut, st, pszClassName, bin_encode());
                if (m_stEnpOut.m_iRet)
                {
                    CT_WARNING(("codesvr bin encode err iRet=%d", m_stEnpOut.m_iRet));
                    CT_TRACE(("datahead Info MsgID = %d MsgType = %d  boby name %s more Info see Trace",
                        m_stDataHead.shMsgID, m_stDataHead.shMsgType));
                    CT_TRACEBINARY(((char *)&m_stDataHead, sizeof(CTMsgHead)));
                    CT_TRACEBINARY(((char *)&st, sizeof(ClassName)));
                    return -1;
                }
            }
            break;
        case CODE_JSON :
            {
                CT_CONVERT_TO_JSON_BEGIN(m_stEnpOut);
                CodeConvert(m_stEnpOut, m_stDataHead, "CTMsgHead", json_encode());
                CodeConvert(m_stEnpOut, st, pszClassName, json_encode());
                if (m_stEnpOut.m_iRet)
                {
                    CT_WARNING(("codesvr json err iRet=%d", m_stEnpOut.m_iRet));
                    CT_TRACE(("datahead Info MsgID = %d MsgType = %d  boby name %s more Info see Trace",
                        m_stDataHead.shMsgID, m_stDataHead.shMsgType));
                    CT_TRACEBINARY(((char *)&m_stDataHead, sizeof(CTMsgHead)));
                    CT_TRACEBINARY(((char *)&st, sizeof(ClassName)));
                    return -1;
                }

                CT_CONVERT_TO_JSON_END(m_stEnpOut);

                //结束符
                char chEndFlag = 0;
                CodeConvert(m_stEnpOut, chEndFlag, "char", bin_encode());
            }
            
            break;
        default:
            CT_WARNING(("recv unknown pkg"));
            return -1;
        }

        m_stEnphead.unDataLength = m_stEnpOut.m_ushPos - sizeof(CEnpNetHead);
        memcpy(m_stEnpOut.m_pszBuf, &m_stEnphead, sizeof(CEnpNetHead));
        m_stEnpBuffOut._offset = m_stEnpOut.m_ushPos;

        return 0;
    }
};

#endif  //__CODESRV_CTRL_H__
